package com.shycloud.mido.organ.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.shycloud.common.minio.service.MinioTemplate;
import com.shycloud.mido.common.core.constant.CommonConstants;
import com.shycloud.mido.common.core.exception.BusinessException;
import com.shycloud.mido.common.core.util.R;
import com.shycloud.mido.common.security.util.SecurityUtils;
import com.shycloud.mido.member.api.entity.MultiAssist;
import com.shycloud.mido.member.api.util.Constant;
import com.shycloud.mido.member.api.util.QrCodeUtil;
import com.shycloud.mido.member.api.util.UUIDUtil;
import com.shycloud.mido.organ.api.dto.*;
import com.shycloud.mido.organ.api.entity.*;
import com.shycloud.mido.organ.api.enums.MessageCodeEnum;
import com.shycloud.mido.organ.api.feign.RemoteMemberService;
import com.shycloud.mido.organ.api.vo.NewStudentDetailVO;
import com.shycloud.mido.organ.api.vo.NewStudentVO;
import com.shycloud.mido.organ.api.vo.NewTeacherVO;
import com.shycloud.mido.organ.api.vo.OrganizationVO;
import com.shycloud.mido.organ.config.QrCodeProperties;
import com.shycloud.mido.organ.mapper.*;
import com.shycloud.mido.organ.service.MemberActivatedService;
import com.shycloud.mido.organ.service.OrganizationService;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 机构业务 controller
 *
 * @author nianhua.jiang
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/new_manage")
public class NewOrganizationController {

	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
	/** 七牛云OSS共通方法 */
	private final MinioTemplate minioTemplate;
	/** 机构业务 mapper */
	private final OrganizationMapper orgMapper;
	/** 机构业务 service */
	private final OrganizationService orgService;
	/** 学生模块 mapper */
	private final StudentDetailedMapper studentMapper;
	/** 教师模块 mapper */
	private final TeacherDetailedMapper teacherMapper;
	/** 用户模块 mapper */
	private final MemberMapper memberMapper;
	/** 用户详情模块 mapper */
	private final MemberDetailInfoMapper memberDetailMapper;
	/** 师生关系模块 mapper */
	private final TeacherStudentMapper teacherStudentMapper;
	/** 纠错大师权限激活模块 service */
	private final MemberActivatedService memberActivatedService;
	/** 会员模块 feign */
	private final RemoteMemberService remoteMemberService;
	private final com.shycloud.mido.member.api.feign.RemoteMemberService remoteMemberServiceMem;
	/** 二维码配置信息 */
	private final QrCodeProperties qrProperties;

	@GetMapping("/getOrgList")
	@ApiOperation("获取机构列表")
	public R<List<OrganizationVO>> getOrgList(OrganizationVO organization) {
		return new R<>(orgMapper.getOrgList(organization));
	}

	@PostMapping("/add")
	public R<Object> addOrganization(@RequestBody OrganizationDTO org) throws Exception {

		// 注 ===> 2021-10-21 更新新的业务机构：合作押金分销商：is_studio = 2 的场合，所以接口修正为 is_studio 前台参数传入

		//=== 2021-07-26 优化创建机构逻辑 =======//
		List<Organization> organizations = orgMapper.selectList(new QueryWrapper<Organization>()
				.eq("phone", org.getPhone()));

		if (organizations.stream().anyMatch(x -> "0".equals(x.getIsStudio())) && "0".equals(org.getIsStudio())) {
			return new R<>(CommonConstants.FAIL, "该手机号已创建过机构, 请重试", false);
		}

		if (organizations.stream().anyMatch(x -> "2".equals(x.getIsStudio())) && "2".equals(org.getIsStudio())) {
			return new R<>(CommonConstants.FAIL, "该手机号已创建过合作商, 请重试", false);
		}

		String userId = orgMapper.getSysUserCount(org.getPhone());

		if (userId == null) {
			//创建后台管理用户
			SysUserDto user = new SysUserDto();
			user.setUsername(org.getPhone());
			String pwdStr = ENCODER.encode(SecurityUtils.DEFAULT_PASSWORD);
			user.setPassword(pwdStr);
			orgMapper.createSysUser(user);
			userId = user.getId();
		}

		//判断是否有机构权限
		int count = orgMapper.checkIsOrgRole(userId);
		if (count == 0) {
			//生成机构权限
			orgMapper.createSysUserRole(userId);
		}
		orgMapper.insert(org);

		//新增合作商二维码
		if (Organization.COOPERATION.equals(org.getIsStudio())) {
			//二维码创建
			try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {

				HttpURLConnection connection = (HttpURLConnection) new URL("http://attachment.joymido.com/logo.jpg").openConnection();
				connection.setReadTimeout(5000);
				connection.setConnectTimeout(5000);
				connection.setRequestMethod("GET");

				if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
					InputStream inputStream = connection.getInputStream();

					//编辑二维码地址
					byte[] createQrCode = QrCodeUtil.createQrCodeWithLogo(bos,
							"https://depositlease.joymido.com/#/?orgId=" + org.getId(),
							1500, "PNG", inputStream);

					ByteArrayInputStream is = new ByteArrayInputStream(createQrCode);
					//调用 OSS
					String uuid32 = UUIDUtil.getUUID32();
					String qrCodeUrl = minioTemplate
							.uploadFileWX(is, Constant.BUCKET_QRCODE_PRE + uuid32 + ".png", qrProperties.getQrcodeBucket(),
									qrProperties.getQrcodeCdn());

					org.setQrCodeUrl(qrCodeUrl);
					orgMapper.updateById(org);
				}
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				throw e;
			}
		}

		//插入归属运营商
		if (null != org.getOptId()) {
			orgMapper.insertOptOrg(org.getOptId(), org.getId());
		}
		return new R<>();
	}

	@PostMapping("/uploadImg")
	@ApiOperation("上传机构营业执照")
	public R<Object> uploadImg(@RequestParam("img") MultipartFile img) {
		// 提取后缀
		// 提取图片名称
		String fileName = img.getOriginalFilename().replace(" ", "");
		String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);

		String uuid = UUID.randomUUID().toString();
		// 提取图片名称
		String imgName = "org-" + uuid.replace("-", "") + "." + suffix;
		// 初始化map结果集
		Map<String, String> resultMap = new HashMap<>(4);
		// 名称
		resultMap.put("name", imgName);
		try {
			// 上传操作
			resultMap.put("url", minioTemplate.uploadFile(img.getInputStream(), imgName));
		} catch (Exception e) {
			return R.builder().code(CommonConstants.FAIL).msg(e.getLocalizedMessage()).build();
		}
		return R.builder().data(resultMap).build();
	}

	@GetMapping("/getOrgStatistics")
	public R<Object> getOrgStatistics(Integer optId) {

		Map<String, String> map = new HashMap<>();
		//机构数量
		String orgNum = orgMapper.getOrgNum(optId, Organization.ORG);
		//工作室数量
		String studioNum = orgMapper.getStudioNum(optId);
		//合作商数量
		String cooperation = orgMapper.getOrgNum(optId, Organization.COOPERATION);
		map.put("orgNum", orgNum);
		//工作室
		map.put("studioNum", studioNum);
		//合作商
		map.put("cooperation", cooperation);
		return new R<>(map);
	}

	@GetMapping("/pageOrg")
	@ApiOperation(value = "分页查询机构")
	public R<IPage<OrganizationDTO>> getOrganPage(Page<OrganizationDTO> page, OrganizationDTO org) {
		return new R<>(orgService.getOrgPage(page, org));
	}

	@GetMapping("/pageStudio")
	@ApiOperation(value = "分页查询工作室")
	public R<IPage<OrganizationDTO>> getStudioPage(Page<OrganizationDTO> page, OrganizationDTO studio) {
		return new R<>(orgService.getStudioPage(page, studio));
	}

	@PostMapping("/updateOrg")
	@ApiOperation("根据id修改机构/工作室")
	public R<Boolean> updateOrg(@RequestBody OrganizationVO org) {
		return new R(orgService.updateOrg(org));
	}

	@GetMapping("/getOrgExtend")
	@ApiOperation("查询机构扩展信息")
	public R<Object> getOrgExtend(Integer orgId) {
		Map<String, Integer> result = new HashMap<>();
		Integer studentNum = orgMapper.getStudentNum(orgId);
		Integer teacherNum = orgMapper.getTeacherNum(orgId);
		result.put("student", studentNum);
		result.put("teacher", teacherNum);
		return new R<>(result);
	}

	@PostMapping("/updateOrgWelcome")
	@ApiOperation("修改机构欢迎语")
	public R<Integer> updateOrgWelcome(@RequestBody Organization org) {
		return new R<>(orgMapper.updateById(org));
	}

	@GetMapping("/getOrgWelcome")
	@ApiOperation("获取机构欢迎语")
	public R<String> getOrgWelcome(Integer orgId) {
		String tag = "";
		if (null != orgMapper.selectById(orgId).getTag()) {
			tag = orgMapper.selectById(orgId).getTag();
		}
		return new R<>(tag);
	}

	@GetMapping("/getStudentList")
	@ApiOperation("获取学生列表")
	public R<IPage<NewStudentVO>> getStudentList(Page<NewStudentVO> page, Integer orgId, String name, String sex, String age) {
		IPage<NewStudentVO> studentList = orgMapper.getStudentList(page, orgId, name, sex, age);
		for (NewStudentVO record : studentList.getRecords()) {
			MultiAssist assistCount = remoteMemberServiceMem.getAssistCount(Constant.ASSIST_SUBJECT_STUDENT, record.getId());
			record.setAssistCount(assistCount == null ? 0 : assistCount.getMonthly());
			record.setAssistEndTime(assistCount == null ? null : assistCount.getEndTime());
		}
		return new R<>(studentList);
	}

	@PostMapping("/addStudent")
	@ApiOperation("新增学生")
	public R<Object> addStudent(@RequestBody AddStudentDTO dto) {

		String phone = dto.getPhone();
		QueryWrapper<MemberEntity> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("username", phone);
		List<MemberEntity> memberList = memberMapper.selectList(queryWrapper);
		String memberId;
		// 1. 没有账号创建member账户
		if (memberList.size() == 0) {
			MemberEntity member = new MemberEntity();
			member.setUsername(phone);
			member.setPhone(phone);
			member.setPassword(ENCODER.encode("123456"));
			member.setShowname(dto.getName());
			memberMapper.insert(member);
			memberId = member.getId();
			MemberDetailInfoEntity detail = new MemberDetailInfoEntity();
			detail.setMemberId(member.getId());
			detail.setBirthday(dto.getBirthday());
			detail.setSex(dto.getSex());
			memberDetailMapper.insert(detail);
		} else {
			if (memberList.size() > 1) {
				return new R<>(CommonConstants.FAIL, "该手机号重复注册", false);
			}
			memberId = memberList.get(0).getId();
			QueryWrapper<StudentDetailedEntity> studentWrapper = new QueryWrapper<>();
			studentWrapper.eq("member_id", memberId);
			studentWrapper.ne("org_id", 0);
			List<StudentDetailedEntity> studentList = studentMapper.selectList(studentWrapper);
			if (studentList.size() > 0) {
				return new R<>().setCode(CommonConstants.FAIL).setMsg("该手机号已绑定教师").setData(false);
			}
		}

		//判断是否是教师账号
		Integer teacherCount = teacherMapper.selectCount(new QueryWrapper<TeacherDetailedEntity>().eq("member_id", memberId));

		if (teacherCount > 0) {
			return new R<>().setCode(CommonConstants.FAIL).setMsg("该账号为教师账号，无法添加成为学生").setData(false);
		}

		// 2. 有账号直接与教师进行关联
		// 2.1 先插入student表,插入前先无脑将student表清除
		studentMapper.delete(new QueryWrapper<StudentDetailedEntity>().eq("member_id", memberId));

		StudentDetailedEntity student = new StudentDetailedEntity();
		student.setMemberId(memberId);
		student.setName(dto.getName());
		student.setRemark(dto.getRemark());
		student.setOrgId(dto.getOrgId());
		studentMapper.insert(student);
		// 2.2 插入teacherStudent表
		TeacherStudentEntity ts = new TeacherStudentEntity();
		ts.setOrgId(dto.getOrgId());
		ts.setStudentId(student.getId());
		ts.setTeacherId(dto.getTeacherId());
		teacherStudentMapper.insert(ts);
		return new R<>("添加成功");
	}

	@GetMapping("/studentDetail")
	@ApiOperation("查看学生详情")
	public R<NewStudentDetailVO> studentDetail(String studentId) {
		return new R<>(orgMapper.getStudentDetail(studentId));
	}

	@PostMapping("/updateStudent")
	@ApiOperation("修改学生信息")
	public R<Integer> updateStudent(@RequestBody StudentDetailedEntity entity) {
		studentMapper.updateById(entity);
		QueryWrapper<TeacherStudentEntity> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("student_id", entity.getId());
		TeacherStudentEntity ts = teacherStudentMapper.selectOne(queryWrapper);
		ts.setTeacherId(entity.getBelongTo());
		return new R<>(teacherStudentMapper.updateById(ts));
	}

	@GetMapping("/deleteStudent")
	@ApiOperation("删除学生")
	public R<Object> deleteStudent(String studentId) {
		studentMapper.deleteById(studentId);
		QueryWrapper<TeacherStudentEntity> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("student_id", studentId);
		teacherStudentMapper.delete(queryWrapper);
		return new R<>();
	}

	@Transactional(rollbackFor = Exception.class)
	public String addTeacherTransactional(AddTeacherDTO dto) {
		// 1. 判断是否有member账号, 没有则创建
		String account = dto.getAccount();
		QueryWrapper<MemberEntity> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("username", account);
		List<MemberEntity> memberList = memberMapper.selectList(queryWrapper);
		String memberId;
		if (memberList.size() == 0) {
			MemberEntity member = new MemberEntity();
			member.setUsername(account);
			member.setPhone(dto.getPhone());
			member.setPassword(ENCODER.encode(dto.getPassword()));
			member.setShowname(dto.getName());
			member.setIsTeacher("1");
			memberMapper.insert(member);
			memberId = member.getId();
		} else {
			if (memberList.size() > 1) {
				throw new BusinessException("该手机号重复注册");
			}
			MemberEntity member = memberList.get(0);
			memberId = member.getId();
			member.setIsTeacher("1");
			memberMapper.updateById(member);
		}
		// 2. 添加教师
		TeacherDetailedEntity teacher = new TeacherDetailedEntity();
		teacher.setOrgId(dto.getOrgId());
		teacher.setMemberId(memberId);
		teacher.setName(dto.getName());
		teacherMapper.insert(teacher);
		// 3. 激活教师账号
		// 判断是否有激活码
		if (StringUtils.isNotBlank(dto.getCode())) {
			QueryWrapper<MemberActivateEntity> codeWrapper = new QueryWrapper<>();
			codeWrapper.eq("actv_code", dto.getCode());
			MemberActivateEntity memberActivateEntity = memberActivatedService.getOne(codeWrapper);
			// 查询激活码是否存在
			if (memberActivateEntity != null) {
				// 查询激活码是否已经被使用(为NUll未被使用)
				if (StringUtils.isEmpty(memberActivateEntity.getMemberId())) {
					memberActivateEntity.setOrgId(dto.getOrgId().toString());
					memberActivateEntity.setUpdateTime(LocalDateTime.now());
					memberActivateEntity.setMemberId(memberId);
					memberActivateEntity.setStartTime(LocalDateTime.now());
					memberActivateEntity.setStatus(dto.getOrgId() == null ? "3" : "1");

					memberActivatedService.saveOrUpdate(memberActivateEntity);
				} else {
					throw new BusinessException(MessageCodeEnum.MASTER_ERROR_127.getMessage());
				}
			} else {
				throw new BusinessException(MessageCodeEnum.MASTER_ERROR_126.getMessage());
			}
		}
		return memberId;
	}

	@PostMapping("/addTeacher")
	@ApiOperation("新增教师")
	public R<Object> addTeacher(@RequestBody AddTeacherDTO dto) {

		//个人工作室无法添加教师
		Organization organization = orgMapper.selectById(dto.getOrgId());

		if ("1".equals(organization.getIsStudio())) {
			return new R<>(CommonConstants.FAIL, "工作室无法添加教师", false);
		}
		dto.setPassword("123456");
		String memberId = this.addTeacherTransactional(dto);
		// 4. 往教师认证表写入数据
		remoteMemberService.addApproval(memberId);

		return new R<>("添加成功");
	}

	private String generateCode(String orgId) {
		StringBuilder code = new StringBuilder();
		Random r = new Random();
		for (int i = 0; i < 3; i++) {
			// 生成[0,9]区间的整数
			int num = r.nextInt(9);
			code.append(num);
		}
		return "700" + orgId + code.toString();
	}

	private Boolean havaRepeat(String code) {
		QueryWrapper<MemberEntity> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("username", code);
		return memberMapper.selectCount(queryWrapper) > 0;
	}

	@GetMapping("/getUniqueId")
	public R<String> getUniqueId(Integer orgId) {
		String code = this.generateCode(orgId.toString());
		while (this.havaRepeat(code)) {
			code = this.generateCode(orgId.toString());
		}
		return new R<>(code);
	}

	/**
	 * 机构后台修改教师信息
	 *
	 * @param teacherId 教师ID
	 * @param name      教师昵称
	 * @param code      code
	 * @return {@link R}
	 * @author nianhua.jiang
	 * @date 2021/10/13 13:03
	 */
	@GetMapping("/updateTeacher")
	public R<Object> updateTeacher(String teacherId, String name, String code) {

		TeacherDetailedEntity teacher = teacherMapper.selectById(teacherId);
		teacher.setName(name);
		teacherMapper.updateById(teacher);

		//code 码不为空则开通硬件 【目前暂无此功能】
		if (StringUtils.isNotBlank(code)) {
			QueryWrapper<MemberActivateEntity> codeWrapper = new QueryWrapper<>();
			codeWrapper.eq("actv_code", code);
			MemberActivateEntity memberActivateEntity = memberActivatedService.getOne(codeWrapper);
			// 查询激活码是否存在
			if (memberActivateEntity != null) {
				// 查询激活码是否已经被使用(为NUll未被使用)
				if (StringUtils.isEmpty(memberActivateEntity.getMemberId())) {
					memberActivateEntity.setOrgId(teacher.getOrgId().toString());
					memberActivateEntity.setUpdateTime(LocalDateTime.now());
					memberActivateEntity.setMemberId(teacher.getMemberId());
					memberActivateEntity.setStartTime(LocalDateTime.now());
					memberActivateEntity.setStatus(teacher.getOrgId() == null ? "3" : "1");

					memberActivatedService.saveOrUpdate(memberActivateEntity);
				} else {
					return new R<>(CommonConstants.FAIL, "激活码已经被使用", false);
				}
			} else {
				return new R<>(CommonConstants.FAIL, "激活码验证失败", false);
			}
		}
		return new R<>("修改成功");
	}

	@GetMapping("/deleteTeacher")
	@ApiOperation("删除教师")
	public R<Integer> deleteTeacher(String teacherId) {
		return new R<>(teacherMapper.deleteById(teacherId));
	}

	@GetMapping("/getTeacherList")
	@ApiOperation("获取教师列表")
	public R<IPage<NewTeacherVO>> getTeacherList(Page<NewTeacherVO> page, Integer orgId, String name, String phone) {
		IPage<NewTeacherVO> pageData = orgMapper.getTeacherList(page, orgId, name, phone);
		for (NewTeacherVO item : pageData.getRecords()) {
			item.setStudentQuantity(orgMapper.getStudentNumByTeacherId(item.getTeacherId()));
		}
		return new R<>(pageData);
	}

	@GetMapping("/stuGetTeacherList")
	@ApiOperation("所属教师列表")
	public R<List<TeacherDetailedEntity>> stuGetTeacherList(Integer orgId) {
		QueryWrapper<TeacherDetailedEntity> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("org_id", orgId);
		return new R<>(teacherMapper.selectList(queryWrapper));
	}

	/**
	 * 教师批量添加学生
	 *
	 * @param dto 学生信息
	 * @return {@link R}
	 */
	@PostMapping("/teacherAddStudentBatch")
	@ApiOperation("教师批量添加学生")
	public R<Object> teacherAddStudentBatch(@RequestBody StudentBatchDTO dto) {
		for (String studentId : dto.getStudentId()) {
			TeacherStudentEntity entity = new TeacherStudentEntity();
			entity.setOrgId(dto.getOrgId());
			entity.setTeacherId(dto.getTeacherId());
			entity.setStudentId(studentId);
			teacherStudentMapper.insert(entity);
		}
		return new R<>();
	}

	@GetMapping("/searchStudent")
	@ApiOperation("搜索添加学生")
	public R<List<NewStudentDetailVO>> searchStudent(Integer orgId, String keyword) {
		return new R<>(orgMapper.searchStudent(orgId, keyword));
	}

	@GetMapping("/updateTeacherPWD")
	@ApiOperation("修改教师账号密码")
	public R<Integer> updateTeacherPwd(String teacherId, String pwd) {
		TeacherDetailedEntity teacher = teacherMapper.selectById(teacherId);
		MemberEntity member = memberMapper.selectById(teacher.getMemberId());
		member.setPassword(ENCODER.encode(pwd));
		return new R<>(memberMapper.updateById(member));
	}

	@GetMapping("/resetTeacherPWD")
	@ApiOperation("重置教师账号密码")
	public R<Integer> resetTeacherPwd(String teacherId) {
		TeacherDetailedEntity teacher = teacherMapper.selectById(teacherId);
		MemberEntity member = memberMapper.selectById(teacher.getMemberId());
		member.setPassword(ENCODER.encode("123456"));
		return new R<>(memberMapper.updateById(member));
	}

	@GetMapping("/getTeacherStudentList")
	@ApiOperation("教师名下的学生列表")
	public R<List<NewStudentDetailVO>> getTeacherStudentList(String teacherId) {
		return new R<>(orgMapper.getTeacherStudentList(teacherId));
	}

	@GetMapping("/updateOldMemberRepeat")
	public R<Object> updateOldMemberRepeat() {
		List<Map<String, String>> oldMemberList = memberMapper.getOldMemberRepeat();
		for (Map<String, String> oldMember : oldMemberList) {
			try {
				QueryWrapper<MemberEntity> queryWrapper = new QueryWrapper<>();
				queryWrapper.eq("username", oldMember.get("phone"));
				queryWrapper.eq("is_old", 1);
				MemberEntity member = memberMapper.selectOne(queryWrapper);
				member.setUsername(member.getUsername() + "_old");
				memberMapper.updateById(member);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return new R<>();
	}

	@GetMapping("getOrgById")
	public R<Object> getOrgById(Integer orgId) {
		return new R<>(orgService.getById(orgId));
	}

}
